#include "stdafx.h"
#include "resource.h"
#include "resource1.h"
#include "utils.h"
#include "menubutton.h"
#include "CGdiPlusBitmap.h"

#define HOVER_TIMER 0x123456

TCHAR MenuButton::m_szClassName[] = _T("MenuButton");
bool MenuButton::m_fRegistered = false;
std::map<HWND, MenuButton*> MenuButton::m_handleMap;

MenuButton::MenuButton( const string_t & buttonName, LPCTSTR lpText, int x, int y, int nWidth, int nHeight, HWND hParent )
{
	m_fButtonType = TEXT_BUTTON;
	m_strButtonName = buttonName;
	m_xPos = x;
	m_yPos = y;
	m_hParent = hParent;

	int len = _tcslen(lpText);
	if (len > MAX_TEXT_LENGTH - 1)
		len = MAX_TEXT_LENGTH  - 1;
	_tcsncpy(m_lpMenuText, lpText, len);
	m_lpMenuText[len] = _T('\0');
	m_fButtonState = NORMAL_STATE;

	if (!m_fRegistered && !RegisterButtonClass())
		return;
	else
		m_fRegistered = true;

	m_hWnd = CreateWindowEx(
		WS_EX_WINDOWEDGE, _T("MenuButton"), NULL, WS_CHILD | WS_TABSTOP | WS_VISIBLE,
		x, y, nWidth, nHeight, hParent, NULL, NULL, NULL);
	if (m_hWnd) {
		//m_handleMap.insert(std::make_pair<HWND, )
		m_handleMap[(HWND)m_hWnd] = this;
		createMenus();
	}
}

MenuButton::MenuButton( const string_t &buttonName, const std::vector<string_t> filePaths, int x, int y, int nWidth, int nHeight, HWND hParent )
{
	m_fButtonType = ICON_BUTTON;
	m_strButtonName = buttonName;
	m_xPos = x;
	m_yPos = y;
	m_hParent = hParent;
	m_buttonFiles = filePaths;
	m_fButtonState = NORMAL_STATE;

	//need to state button
	if (!m_fRegistered && !RegisterButtonClass())
		return;
	else
		m_fRegistered = true;

	m_hWnd = CreateWindowEx(
		WS_EX_WINDOWEDGE, _T("MenuButton"), NULL, WS_CHILD | WS_TABSTOP | WS_VISIBLE,
		x, y, nWidth, nHeight, hParent, NULL, NULL, NULL);
	if (m_hWnd) {
		//m_handleMap.insert(std::make_pair<HWND, )
		m_handleMap[(HWND)m_hWnd] = this;
		createMenus();
		createIcons();
	}
}

bool MenuButton::RegisterButtonClass()
{
	WNDCLASS wndclass;

	wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
	wndclass.lpfnWndProc   = &MenuButton::WndProc ;
	wndclass.cbClsExtra    = 0 ;
	wndclass.cbWndExtra    = 0 ;
	wndclass.hInstance     = NULL ;
	wndclass.hIcon         = NULL;
	wndclass.hCursor       = NULL;
	//wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
	wndclass.hbrBackground = (HBRUSH) GetStockObject (NULL_BRUSH);
	//wndclass.hbrBackground = NULL;
	wndclass.lpszMenuName  = NULL ;
	wndclass.lpszClassName = m_szClassName ;

	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("menu button could not register class"), 
			m_szClassName, MB_ICONERROR) ;
		return false ;
	}
	return true;
}

LRESULT CALLBACK MenuButton::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC         hdc ;
	PAINTSTRUCT ps ;
	RECT        rect ;
	TCHAR		szBuf[MAX_PATH];
	HRESULT		hr;

	int wmId, wmEvent;
	LRESULT result = 0;


	GetClientRect(hwnd, &rect);
	switch (message)
	{
	case WM_CREATE:
		//CreateToolBar(hwnd);
		SetTimer(hwnd, HOVER_TIMER, 0x100, NULL );
		return 0;

	case WM_PAINT: 
		{
			hdc = BeginPaint (hwnd, &ps) ;
			MenuButton *menuButton = m_handleMap[hwnd];
			menuButton->PaintMenuButton(hwnd, hdc);
			EndPaint (hwnd, &ps) ;
			return 0 ;
		}

	case WM_DESTROY:
		PostQuitMessage (0) ;
		return 0 ;

	case WM_MOUSEMOVE:
		{
			MenuButton *menuButton = m_handleMap[hwnd];
			menuButton->OnMouseMove(hwnd, wParam, lParam);
			break;
		}
	case WM_MOUSELEAVE:
		{
			MenuButton *menuButton = m_handleMap[hwnd];
			menuButton->OnMouseLeave(hwnd, wParam, lParam);
			break;
		}
	
	case WM_TIMER:
		{
			MenuButton *menuButton = m_handleMap[hwnd];
			menuButton->OnTimer(hwnd, wParam, lParam);
			break;
		}
	case WM_LBUTTONDOWN:
		{
			MenuButton *menuButton = m_handleMap[hwnd];
			menuButton->OnLButtonDown(hwnd, wParam, lParam);
			break;
		}
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

void MenuButton::PaintMenuButton( HWND hwnd, HDC hdc )
{
	if (m_fButtonType == TEXT_BUTTON) 
		PaintTextButton(hwnd, hdc);
	else if (m_fButtonType == ICON_BUTTON)
		PaintIconButton(hwnd, hdc);
}

void MenuButton::PaintTextButton( HWND hwnd, HDC hdc )
{
	
	RECT rcClient;
	GetClientRect(hwnd, &rcClient);    
	HTHEME hTheme = OpenThemeData(NULL, L"CompositedWindow::Window");
	if (hTheme)
	{
		HDC hdcPaint = CreateCompatibleDC(hdc);
		if (hdcPaint)
		{
			int cx = RectWidth(rcClient);
			int cy = RectHeight(rcClient);            

			// Define the BITMAPINFO structure used to draw text.
			// Note that biHeight is negative. This is done because
			// DrawThemeTextEx() needs the bitmap to be in top-to-bottom
			// order.

			VsOutput(_T("menu button client : width: %d, height: %d\n"), cx, cy);

			BITMAPINFO dib = { 0 };
			dib.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
			dib.bmiHeader.biWidth           = cx;
			dib.bmiHeader.biHeight          = -cy;
			dib.bmiHeader.biPlanes          = 1;
			dib.bmiHeader.biBitCount        = BIT_COUNT;
			dib.bmiHeader.biCompression     = BI_RGB;            

			HBITMAP hbm = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);

			if (hbm)
			{
				// Setup the theme drawing options.
				HBITMAP hbmOld = (HBITMAP)SelectObject(hdcPaint, hbm);   
				
				LOGFONT lgFont;
				HFONT hFont = NULL, hFontOld;
				HRESULT hrFont = GetThemeSysFont(hTheme, TMT_CAPTIONFONT, &lgFont);
				if (FAILED(hrFont)) 
					hrFont = GetThemeFont(hTheme, hdc, WP_CAPTION, CS_ACTIVE, TMT_CAPTIONFONT ,&lgFont);

				if (SUCCEEDED(hrFont)) {
					//lgFont.lfUnderline = true;
					hFont = CreateFontIndirect(&lgFont);
					if (hFont)
						hFontOld = (HFONT) SelectObject(hdcPaint, hFont);
				} else {
					//else use default gui font
					hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
					if (hFont) {
						GetObject ( hFont, sizeof(LOGFONT), &lgFont ); 
						//lgFont.lfUnderline = true;
						hFont = CreateFontIndirect(&lgFont);
						hFontOld = (HFONT) SelectObject(hdcPaint, hFont);
					}
				}

				//SetTextColor(hdcPaint, RGB(0x00, 0x00, 0x00));
				//DrawText(hdcPaint, m_lpMenuText, -1, &rcClient, DT_CENTER);
				SetBkMode(hdcPaint, TRANSPARENT);

				RECT rcPaint = rcClient;
				rcPaint.top += 8;
				//rcPaint.right -= 125;
				//rcPaint.left = 
				rcPaint.bottom = 50;

				if (m_fButtonState == NORMAL_STATE) {
					DTTOPTS DttOpts = {sizeof(DTTOPTS)};
					//DttOpts.dwFlags = DTT_COMPOSITED;
					DttOpts.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE;
					DttOpts.iGlowSize = 0;

					DrawThemeTextEx(hTheme, 
						hdcPaint, 
						//WP_CAPTION, CS_INACTIVE, 
						BP_PUSHBUTTON, PBS_DEFAULTED,
						m_lpMenuText, 
						-1, 
						DT_CENTER | DT_VCENTER | DT_WORD_ELLIPSIS, 
						&rcPaint, 
						&DttOpts);                
				} else if (m_fButtonState == HOVER_STATE)  {
					DTTOPTS DttOpts = {sizeof(DTTOPTS)};
					//DttOpts.dwFlags = DTT_COMPOSITED;
					DttOpts.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE | DTT_TEXTCOLOR;
					DttOpts.iGlowSize = 15;
					DttOpts.crText = RGB(0xff, 0x00, 0x00); 

					DrawThemeTextEx(hTheme, 
						hdcPaint, 
						//WP_CAPTION, CS_INACTIVE, 
						BP_PUSHBUTTON, PBS_DEFAULTED,
						m_lpMenuText, 
						-1, 
						DT_CENTER | DT_VCENTER | DT_WORD_ELLIPSIS, 
						&rcPaint, 
						&DttOpts);                
				}

				// Blit text to the frame.
				BitBlt(hdc, 0, 0, cx, cy, hdcPaint, 0, 0, SRCCOPY);                

				if (hFont)
				{
					SelectObject(hdcPaint, hFontOld);
					DeleteObject(hFont);
				}
				SelectObject(hdcPaint, hbmOld);
				DeleteObject(hbm);
			}
			DeleteDC(hdcPaint);
		}
		CloseThemeData(hTheme);
	}
}

void MenuButton::PaintIconButton( HWND hwnd, HDC hdc )
{
	RECT rcClient;
	GetClientRect(hwnd, &rcClient);    
	HTHEME hTheme = OpenThemeData(NULL, L"CompositedWindow::Window");
	if (hTheme)
	{
		HDC hdcPaint = CreateCompatibleDC(hdc);
		if (hdcPaint)
		{
			int cx = RectWidth(rcClient);
			int cy = RectHeight(rcClient);            

			// Define the BITMAPINFO structure used to draw text.
			// Note that biHeight is negative. This is done because
			// DrawThemeTextEx() needs the bitmap to be in top-to-bottom
			// order.

			VsOutput(_T("menu button client : width: %d, height: %d\n"), cx, cy);

			BITMAPINFO dib = { 0 };
			dib.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
			dib.bmiHeader.biWidth           = cx;
			dib.bmiHeader.biHeight          = -cy;
			dib.bmiHeader.biPlanes          = 1;
			dib.bmiHeader.biBitCount        = BIT_COUNT;
			dib.bmiHeader.biCompression     = BI_RGB;            

			HBITMAP hbm = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);

			if (hbm)
			{
				// Setup the theme drawing options.
				HBITMAP hbmOld = (HBITMAP)SelectObject(hdcPaint, hbm);   
				
				LOGFONT lgFont;
				HFONT hFont = NULL, hFontOld;
				HRESULT hrFont = GetThemeSysFont(hTheme, TMT_CAPTIONFONT, &lgFont);
				if (FAILED(hrFont)) 
					hrFont = GetThemeFont(hTheme, hdc, WP_CAPTION, CS_ACTIVE, TMT_CAPTIONFONT ,&lgFont);

				if (SUCCEEDED(hrFont)) {
					//lgFont.lfUnderline = true;
					hFont = CreateFontIndirect(&lgFont);
					if (hFont)
						hFontOld = (HFONT) SelectObject(hdcPaint, hFont);
				} else {
					//else use default gui font
					hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
					if (hFont) {
						GetObject ( hFont, sizeof(LOGFONT), &lgFont ); 
						//lgFont.lfUnderline = true;
						hFont = CreateFontIndirect(&lgFont);
						hFontOld = (HFONT) SelectObject(hdcPaint, hFont);
					}
				}

				//SetTextColor(hdcPaint, RGB(0x00, 0x00, 0x00));
				//DrawText(hdcPaint, m_lpMenuText, -1, &rcClient, DT_CENTER);
				SetBkMode(hdcPaint, TRANSPARENT);

				RECT rcPaint = rcClient;
				rcPaint.top += 8;
				//rcPaint.right -= 125;
				//rcPaint.left = 
				rcPaint.bottom = 50;

				//draw the icon button
				Graphics graphics(hdcPaint);
				if (m_fButtonState == NORMAL_STATE) {
					Status status = graphics.DrawImage(*(m_buttonImages.at(0)), 0, 5, 18, 18);
					assert(status == Ok);
				} else if (m_fButtonState == HOVER_STATE)  {
					Status status = graphics.DrawImage(*(m_buttonImages.at(1)), 0, 5, 18, 18);
					assert(status == Ok);
				}

				// Blit text to the frame.
				BitBlt(hdc, 0, 0, cx, cy, hdcPaint, 0, 0, SRCCOPY);                

				if (hFont)
				{
					SelectObject(hdcPaint, hFontOld);
					DeleteObject(hFont);
				}
				SelectObject(hdcPaint, hbmOld);
				DeleteObject(hbm);
			}
			DeleteDC(hdcPaint);
		}
		CloseThemeData(hTheme);
	}
}

void MenuButton::OnMouseMove( HWND hwnd, WPARAM wParam, LPARAM lParam )
{
	if (m_fButtonState != HOVER_STATE) {
		m_fButtonState = HOVER_STATE;
		InvalidateRect(hwnd, NULL, FALSE);
		//TRACKMOUSEEVENT tme;
		//tme.cbSize = sizeof(TRACKMOUSEEVENT);
		//tme.dwFlags = TME_HOVER | TME_LEAVE | TME_NONCLIENT;
		//tme.hwndTrack = hwnd;
		//tme.dwHoverTime = 0;
		//TrackMouseEvent(&tme);
	}
	
	//VsOutput(_T("Menu Button onMouseMove\n"));
}

void MenuButton::OnMouseLeave( HWND hwnd, WPARAM wParam, LPARAM lParam )
{
	VsOutput(_T("Menu Button onMouseLeave\n"));
	//m_fButtonState = NORMAL_STATE;
	InvalidateRect(hwnd, NULL, FALSE);
}

void MenuButton::OnTimer( HWND hwnd, WPARAM wParam, LPARAM lParam )
{
	//VsOutput(_T("Menu Button onTimer\n"));
	if (wParam == HOVER_TIMER) {
		POINT point;
		RECT rect;
		GetCursorPos(&point);
		ScreenToClient(hwnd, &point);
		GetClientRect(hwnd, &rect);
		if (PtInRect(&rect, point)) {
			VsOutput(_T("fuckfuck\n"));
			BUTTON_STATE oldState = m_fButtonState;
			if (oldState != HOVER_STATE) {
				m_fButtonState = HOVER_STATE;
				InvalidateRect(hwnd, NULL, FALSE);
			}
		} else {
			BUTTON_STATE oldState = m_fButtonState;
			if (oldState != NORMAL_STATE) {
				m_fButtonState = NORMAL_STATE;
				InvalidateRect(hwnd, NULL, FALSE);
			}
		}
	}
}

void MenuButton::OnLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
{
	if (m_fButtonType == TEXT_BUTTON) {
		VsOutput(_T("Menu Button onLButtonDown\n"));
		// Display the menu

		int xPos = GET_X_LPARAM(lParam); 
		int yPos = GET_Y_LPARAM(lParam); 
		VsOutput(_T("Cursor position x = %d, y = %d"), xPos, yPos);
		POINT point;
		point.x = xPos;
		point.y = yPos;
		ClientToScreen(m_hWnd, &point);
		TrackPopupMenu( m_hMenu, 0, point.x, point.y, 0, m_hWnd, NULL);
	} else {
		MessageBox(hwnd, m_strButtonName.c_str(), m_strButtonName.c_str(), 0);
	}
}

void MenuButton::createMenus()
{
	m_hMenu = CreatePopupMenu();
	AppendMenu (m_hMenu, MF_STRING,    IDM_FILE_NEW,     _T("&New") );
	AppendMenu (m_hMenu, MF_STRING,    IDM_FILE_OPEN,    _T("&Open...") );
	AppendMenu (m_hMenu, MF_STRING,    IDM_FILE_SAVE,    _T("&Save") );
	AppendMenu (m_hMenu, MF_STRING,    IDM_FILE_SAVE_AS, _T("Save &As...") );
	AppendMenu (m_hMenu, MF_SEPARATOR, 0,                NULL);
	AppendMenu (m_hMenu, MF_STRING,    IDM_APP_EXIT,     _T("E&xit") );
	
}

void MenuButton::createIcons()
{
	for (size_t i = 0; i < m_buttonFiles.size(); ++i) {
		CGdiPlusBitmap *pBitmap = new CGdiPlusBitmap;
		if (pBitmap->Load(m_buttonFiles.at(i).c_str())) {
			m_buttonImages.push_back(pBitmap);
		} else {
			VsOutput(_T("fuck cannot load png image"));
		}
	}
}